package com.example.circuitbreaker.demo;

import lombok.Data;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 类描述:     [一句话描述该类的功能]
 * 项目名：    circuitbreaker
 * 项目包名：  com.example.circuitbreaker.demo
 * 创建人:     方豪   
 * 创建时间:   2021/4/2 18:33  
 * 版本:      [v1.0]   
 */

@Data
public abstract class CircuitBreaker {
    //执行次数阈值
    private int totalCountThreshold;
    //执行失败次数阈值
    private int failCountThreshold;
    //延迟时间(秒)，表示打开后多久自动合上
    private int timeoutSeconds;
    //断路器开启标识
    private AtomicBoolean circuitOpen = new AtomicBoolean(false);
    //实际执行次数
    private AtomicInteger totalCount = new AtomicInteger();
    //实际失败次数
    private AtomicInteger failCount = new AtomicInteger();
    //断路器上次开启时间
    private AtomicLong lastOpenTime = new AtomicLong();

    public CircuitBreaker(int totalCountThreshold, int failCountThreshold, int timeoutSeconds) {
        this.totalCountThreshold = totalCountThreshold;
        this.failCountThreshold = failCountThreshold;
        this.timeoutSeconds = timeoutSeconds;
    }

    /**
     * 判断是否开启断路器
     * @return
     */
    public boolean isOpen() {
        if (this.circuitOpen.get()) {
            return true;
        } else {
            if (this.totalCount.get() < this.totalCountThreshold) {
                return false;
            } else if (this.failCount.get() < this.failCountThreshold) {
                return false;
            } else if (this.circuitOpen.compareAndSet(false, true)) {
                this.lastOpenTime.set(System.currentTimeMillis());
                return true;
            } else {
                return true;
            }
        }
    }

    /**
     * 关闭断路器
     */
    public void close() {
        if (this.circuitOpen.get()) {
            this.circuitOpen.compareAndSet(true, false);
        }
    }

    /**
     * 打开断路器
     */
    public void open() {
        if (!this.circuitOpen.get()) {
            this.circuitOpen.compareAndSet(false, true);
        }
    }

    /**
     * 判断是否可以正常执行任务
     * @return
     */
    public boolean allowExecute() {
        return !this.isOpen() || this.isTimeout();
    }

    /**
     * 判断断路器开启时间是否超过延迟时间
     * @return
     */
    private boolean isTimeout() {
        long lastOpen = this.lastOpenTime.get();
        if(this.circuitOpen.get() && System.currentTimeMillis() > lastOpen + timeoutSeconds*1000L){
            this.close();
            this.lastOpenTime.compareAndSet(lastOpen, System.currentTimeMillis());
            this.totalCount.compareAndSet(totalCount.get(),0);
            this.failCount.compareAndSet(failCount.get(),0);
            System.out.println("========断路器的超时时间到了，关闭断路器，开始正常执行任务，并重置已执行的次数=======");
            return true;
        }
        return false;
    }

    /**
     * 执行失败策略
     */
    public abstract void fallback();

}
